

#include <unistd.h>
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <pthread.h>
#include <netinet/in.h>
#include <sys/time.h>
#include "radius.h"

#ifndef u_char
typedef unsigned char u_char;
#endif

#define coa_req             coa_rep
#define COA_ACK             0
#define COA_NAK             1
#define COA_MSG             2
#define DISCONNECTION_MSG   3



// 各消息域在消息中的起始位置
#define POS_CODE	0		/* Message code */
#define POS_IDENT	1		/* Identifier */
#define POS_LENGTH	2		/* Message length */
#define POS_AUTH	4		/* Authenticator */
#define LEN_AUTH	16		/* Length of authenticator */
#define POS_ATTRS	20		/* Start of attributes */

//  Radius client句柄类型
#define RADCLT_AUTH	1
#define RADCLT_ACCT	2
#define RADCLT_DROP	3
#define RADCLT_COA      4

#define MY_VENDOR_ID            60000

//  用户认证密码类型
#define CLEAR_PASSWORD		RAD_USER_PASSWORD
#define CHAP_PASSWORD		RAD_CHAP_PASSWORD


//  Radius记账状态
#define ACCT_START			RAD_START
#define ACCT_STOP			RAD_STOP
#define ACCT_UPDATE			RAD_UPDATE

//  Radius相关端口
#define RAD_AUTH_PORT	1812
#define RAD_ACCT_PORT	1813
#define RAD_COA_PORT	3799

//  ZTE限速
#define ZTE_RATE_DOWN	83
#define ZTE_RATE_UP		89

//  限速属性
#define RAD_RATE_DOWN	1
#define RAD_RATE_UP		2

// 流量配额
#define RAD_MAX_FLOW		10 	/* Integer */
#define RAD_MAX_GIGA_FLOW	11  /* Integer */

#define  RAD_ADJUST_DATA_QUOTA     14
#define  RAD_ADJUST_GIGA_DATA_QUOTA     21

// 类型流量
#define NATSHELL_DAY_LIMIT_FLOW		12
#define NATSHELL_MON_LIMIT_FLOW		13
#define RAD_TYPEDATA_URL	5	/* String */

//  Radius client句柄结构
typedef struct radclt_handle{
	int fd;						//  当前通信socket
	int type;					//  当前句柄提供的服务
	int ident; 					//  当前消息标识符值
	uint32_t nasip;				//  NAS IP地址
	uint32_t vendor;			//  厂商代码
	char *secret; 				//  共享密钥
	int secretlen;				//  共享密钥长度
	uint32_t timeout; 			//  接收消息超时时间,单位毫秒
	pthread_mutex_t idlock;		//  消息标识锁(用于并发情况下)
	struct sockaddr_in addr; 	//  Radius服务器通信地址
}radclt_t;

//  消息类型
#define RADMSG_IN	1
#define RADMSG_OUT	2

typedef struct radclt_msg {
	uint8_t buf[MSGSIZE];
	uint8_t auth[LEN_AUTH];			//  鉴别码
	struct sockaddr_in from; 		//  消息来源
	uint8_t code;  					//  消息code
	uint8_t ident;					//  消息标识
	uint8_t flag; 					//  消息标志
	int len;
	int off;
}radmsg_t;




struct coa_rep{
    int coa_flag;
    radmsg_t  msg;
};

typedef struct radven_attr {
	uint32_t ident;
	int off;
	uint8_t flag;
	uint8_t type;
	uint8_t len;
	uint8_t *value;
} radven_t;

radclt_t *radclt_open(uint32_t type, const char *host, uint16_t port,
					    const char *secret, const char *nasip,
					    uint32_t msto, int nonblock);

//  认证句柄
static inline radclt_t *radclt_open_auth(const char *host, const char *secret, const uint16_t port,
							const char *nasip, uint32_t msto, int nonblock)
{
	return radclt_open(RADCLT_AUTH, host, port, secret, nasip, msto, nonblock);
}

//  计费句柄
static inline radclt_t *radclt_open_acct(const char *host, const char *secret, const uint16_t port,
							const char *nasip,  uint32_t msto, int nonblock)
{
	return radclt_open(RADCLT_ACCT, host, port, secret, nasip, msto, nonblock);
}

//  DM句柄
static inline radclt_t *radclt_open_drop(const char *host, const char *secret,
							const char *nasip,  uint32_t msto, int nonblock)
{
	return radclt_open(RADCLT_DROP, host, RAD_COA_PORT, secret, nasip, msto, nonblock);
}

//  销毁Radius句柄
void radclt_close(radclt_t **h);

//  发送消息
int radclt_send(radclt_t *h, radmsg_t *m);

//  返回DM消息
int radclt_drop_rep(radclt_t *h, uint8_t code, radmsg_t *m, struct sockaddr_in *dst);


int radclt_coa_rep(radclt_t *h, uint8_t code, radmsg_t *m, struct sockaddr_in *dst);


static inline int radcliDMACKRep(radclt_t *h, radmsg_t *m, struct sockaddr_in *from)
{
	return radclt_drop_rep(h, RAD_DISCONNECT_ACK, m, from);
}

static inline int radcliDMNAKRep(radclt_t *h, radmsg_t *m, struct sockaddr_in *from)
{
	return radclt_drop_rep(h, RAD_DISCONNECT_NAK, m, from);
}
static inline int radcliCOAACKRep(radclt_t *h, radmsg_t *m, struct sockaddr_in *from)
{
	return radclt_coa_rep(h, RAD_COA_ACK, m, from);
}

static inline int radcliCOANAKRep(radclt_t *h, radmsg_t *m, struct sockaddr_in *from)
{
	return radclt_drop_rep(h, RAD_COA_NAK, m, from);
}
//  接收消息
int radclt_recv(radclt_t *h, radmsg_t *m);

int radmsg_calc_auth(radclt_t *h, uint8_t *auth, radmsg_t *);

//  验证请求消息是否合法
int radmsg_is_valid_req(radclt_t *h, radmsg_t *m);

//  验证收到的回复消息正确性
int radmsg_is_valid_rep(radclt_t *h, uint8_t *auth, radmsg_t *m);

//  获取消息属性
int radmsg_get_attr(radmsg_t *m, void **value, int *len);

//  解析厂商私有属性
int radmsg_get_vendor_attr(uint8_t *buf, int len, radven_t *attr);


int radmsg_init_req(radclt_t *h, radmsg_t *m, uint8_t code);
int radmsg_put_uint8(radmsg_t *m, uint8_t type, uint8_t v);
int radmsg_put_uint16(radmsg_t *m, uint8_t type, uint16_t v);
int radmsg_put_uint32(radmsg_t *m, uint8_t type, uint32_t v);
int radmsg_put_v4ip(radmsg_t *m, uint8_t type, uint32_t ip);
int radmsg_put_str(radmsg_t *m, uint8_t type, const char *v, int len);

int radmsg_get_int32(void *v, int len);

static inline void radmsg_zero(radmsg_t *m)
{
	memset(m, 0, sizeof(radmsg_t));
}

//  初始化认证请求消息
static inline int radmsg_init_req_auth(radclt_t *h, radmsg_t *m)
{
	return radmsg_init_req(h, m, RAD_ACCESS_REQUEST);
}

//  初始化计费请求消息
static inline int radmsg_init_req_acct(radclt_t *h, radmsg_t *m)
{
	return radmsg_init_req(h, m, RAD_ACCOUNTING_REQUEST);
}

//  初始化开始记账消息
static inline int radmsg_init_req_acct_start(radclt_t *h, radmsg_t *m)
{
	if (radmsg_init_req(h, m, RAD_ACCOUNTING_REQUEST)) {
		return -1;
	}
	return radmsg_put_uint32(m, RAD_ACCT_STATUS_TYPE, ACCT_START);
}

//  初始化更新记账消息
static inline int radmsg_init_req_acct_update(radclt_t *h, radmsg_t *m)
{
	if (radmsg_init_req(h, m, RAD_ACCOUNTING_REQUEST)) {
		return -1;
	}
	return radmsg_put_uint32(m, RAD_ACCT_STATUS_TYPE, ACCT_UPDATE);
}

//  初始化停止记账消息
static inline int radmsg_init_req_acct_stop(radclt_t *h, radmsg_t *m)
{
	if (radmsg_init_req(h, m, RAD_ACCOUNTING_REQUEST)) {
		return -1;
	}
	return radmsg_put_uint32(m, RAD_ACCT_STATUS_TYPE, ACCT_STOP);
}

////////////////////////////////////////////////////////////////////////

//  添加用户名
static inline int radmsg_put_user_name(radmsg_t *m, const char *name, int len)
{
	return radmsg_put_str(m, RAD_USER_NAME, name, len);
}

//  添加用户PAP密码
int radmsg_put_pap_pwd(radclt_t *h, radmsg_t *m, const char *pwd, int len);

//  添加用户CHAP密码
static inline int radmsg_put_chap_pwd(radmsg_t *m, const char *pwd, int len)
{
	return radmsg_put_str(m, RAD_CHAP_PASSWORD, pwd, len);
}

//  添加用户IP地址
static inline int radmsg_put_user_ip(radmsg_t *m, uint32_t ip)
{
	return radmsg_put_v4ip(m, RAD_FRAMED_IP_ADDRESS, ip);
}

//  添加用户MAC
static inline int radmsg_put_user_mac(radmsg_t *m, const char *mac)
{
	return radmsg_put_str(m, RAD_CALLING_STATION_ID, mac, 17);
}

//  添加NAS IP地址
static inline int radmsg_put_nas_ip(radmsg_t *m, uint32_t ip)
{
	return radmsg_put_v4ip(m, RAD_NAS_IP_ADDRESS, ip);
}

//  添加计费会话Id
static inline int radmsg_put_acct_sess_id(radmsg_t *m, const char *id, int len)
{
	return radmsg_put_str(m, RAD_ACCT_SESSION_ID, id, len);
}
// 添加called id
static inline int radmsg_put_called_id(radmsg_t *m, const char *id, int len)
{
	return radmsg_put_str(m, RAD_CALLED_STATION_ID, id, len);
}


//  添加认证类型
static inline int radmsg_put_auth_type(radmsg_t *m, uint32_t type)
{
	return radmsg_put_uint32(m, RAD_ACCT_AUTHENTIC, type);
}
//  添加RADIUS认证类型
static inline int radmsg_put_auth_radius(radmsg_t *m)
{
	return radmsg_put_uint32(m, RAD_ACCT_AUTHENTIC, RAD_AUTH_RADIUS);
}

//  添加在线时长
static inline int radmsg_put_online_time(radmsg_t *m, uint32_t t)
{
	return radmsg_put_uint32(m, RAD_ACCT_SESSION_TIME, t);
}

// 添加用户下行GB流量
static inline int radmsg_put_giga_input(radmsg_t *m, uint32_t v)
{
	return radmsg_put_uint32(m, RAD_ACCT_INPUT_GIGAWORDS, v);
}

// 添加用户下行字节流量
static inline int radmsg_put_byte_input(radmsg_t *m, uint32_t v)
{
	return radmsg_put_uint32(m, RAD_ACCT_INPUT_OCTETS, v);
}

// 添加用户上行GB流量
static inline int radmsg_put_giga_output(radmsg_t *m, uint32_t v)
{
	return radmsg_put_uint32(m, RAD_ACCT_OUTPUT_GIGAWORDS, v);
}

// 添加用户上行字节流量
static inline int radmsg_put_byte_output(radmsg_t *m, uint32_t v)
{
	return radmsg_put_uint32(m, RAD_ACCT_OUTPUT_OCTETS, v);
}
//	radius 认证

